package com.ffcs.cn.action.base.tree;

import com.supermap.desktop.controls.ui.controls.SmDialog;
import com.supermap.desktop.core.Application;
import com.supermap.desktop.core.copycutpaste.SmTransferable;
import com.supermap.desktop.core.ui.controls.GridBagConstraintsHelper;
import com.supermap.desktop.core.uicolorscheme.componentColors.DesktopListSchemeColor;
import com.supermap.desktop.core.utilties.ColorUtilities;
import com.supermap.desktop.core.utilties.LogUtilities;
import com.ffcs.cn.DevelopProperties;

import javax.swing.*;
import javax.swing.tree.DefaultMutableTreeNode;
import javax.swing.tree.DefaultTreeModel;
import javax.swing.tree.TreePath;
import java.awt.*;
import java.awt.datatransfer.DataFlavor;
import java.awt.datatransfer.Transferable;
import java.awt.dnd.*;

public class DialogJTreeDragSort extends SmDialog {
	private JTree tree;
	// 定义拖拽的数据类型，不同数据节点可以用不同的定义，方便接收推拽的控件判别是不是自己想要的数据
	public static final DataFlavor TREE_SORT_DRAG_NODE = new DataFlavor(DialogJTreeDragSort.class, "DialogJTreeDragTreeNode");

	public DialogJTreeDragSort() {
		//设置标题
		setTitle("拖拽调整节点顺序示例");
		//初始化使用控件
		initComponents();
		//初始化布局，并添加控件
		initLayout();
		// 初始化拖拽
		initDrag();
		//设置初始化窗口大小
		Dimension dimension = new Dimension(350, 560);
		setSize(dimension);
		//设置最小窗口
		setMinimumSize(dimension);
	}

	private void initComponents() {
		//创建节点
		DefaultMutableTreeNode workspaceNode = new DefaultMutableTreeNode("工作空间");

		DefaultMutableTreeNode datasourceNode = new DefaultMutableTreeNode(DevelopProperties.getString("String_DatasourceName"));
		//添加子节点
		datasourceNode.add(new DefaultMutableTreeNode("DataSource1"));
		datasourceNode.add(new DefaultMutableTreeNode("DataSource2"));
		datasourceNode.add(new DefaultMutableTreeNode("DataSource3"));

		DefaultMutableTreeNode mapNode = new DefaultMutableTreeNode("地图");
		mapNode.add(new DefaultMutableTreeNode("Map1"));
		mapNode.add(new DefaultMutableTreeNode("Map2"));
		mapNode.add(new DefaultMutableTreeNode("Map3"));

		DefaultMutableTreeNode layoutNode = new DefaultMutableTreeNode("布局");
		layoutNode.add(new DefaultMutableTreeNode("Layout1"));
		layoutNode.add(new DefaultMutableTreeNode("Layout2"));
		layoutNode.add(new DefaultMutableTreeNode("Layout3"));

		workspaceNode.add(datasourceNode);
		workspaceNode.add(mapNode);
		workspaceNode.add(layoutNode);

		//创建树
		this.tree = new JTree(workspaceNode);
		//树根节点不显示
		this.tree.setRootVisible(false);
		this.tree.setShowsRootHandles(true);
	}

	private void initLayout() {
		//设置布局为 GridBagLayout 布局
		this.setLayout(new GridBagLayout());
		//将 tree 添加到滚动面板中
		JScrollPane scrollPanelTree = new JScrollPane(tree);
		scrollPanelTree.setBorder(BorderFactory.createTitledBorder(DevelopProperties.getString("String_DragSortTreeNode")));
		//添加滚动面板
		this.add(scrollPanelTree, new GridBagConstraintsHelper(0, 0, 1, 1).setWeight(1, 1)
				.setInsets(GridBagConstraintsHelper.FRAME_CONTROL_GAP, GridBagConstraintsHelper.FRAME_CONTROL_GAP, 0, GridBagConstraintsHelper.CONTROLS_GAP)
				.setFill(GridBagConstraints.BOTH));
	}

	private void initDrag() {
		this.tree.setDragEnabled(true);// 开启拖拽
		this.tree.setTransferHandler(new TreeTransferHandler());// 树绑定TransferHandler，可以自定义从树拖拽出去的内容，方便拖拽接收目标解析
		new DropTarget(this.tree, new TreeDropTargetAdapter());// 树绑定拖拽目标事件，绑定后树可以解析拖拽东西到树的行为
	}

	// 根据树节点 userObject 查找对应的树节点，注意：树节点userObject需要具有唯一性
	private DefaultMutableTreeNode findTreeNode(DefaultMutableTreeNode defaultMutableTreeNode, Object userObject) {
		if (defaultMutableTreeNode.getUserObject().equals(userObject)) {
			return defaultMutableTreeNode;
		}
		if (defaultMutableTreeNode.getChildCount() > 0) {
			for (int i = 0; i < defaultMutableTreeNode.getChildCount(); i++) {
				DefaultMutableTreeNode treeNode = findTreeNode((DefaultMutableTreeNode) defaultMutableTreeNode.getChildAt(i), userObject);
				if (treeNode != null) {
					return treeNode;
				}
			}
		}
		return null;
	}


	class TreeDropTargetAdapter extends DropTargetAdapter {
		private Rectangle recordBounds = null;// 用于存上一次绘制拖拽标识线的矩形范围
		private boolean isUp = false;// 判断拖拽的东西的目标节点向上还是向下移动
		private final Color MOVE_COLOR = DesktopListSchemeColor.instance.getTreeMoveLineColor();// 绘制移动时线段颜色

		// 判断是否支持拖拽
		private boolean isDropAcceptable(DropTargetDropEvent event) {
			return (event.getDropAction() & DnDConstants.ACTION_COPY_OR_MOVE) != 0;
		}

		@Override
		public void dragExit(DropTargetEvent dte) {
			// 拖拽退出时清除绘制拖拽标识线
			clearRecordBounds((Graphics2D) getGraphics());
		}

		@Override
		public void dragOver(DropTargetDragEvent dtde) {
			Transferable transferable = null;
			try {
				transferable = dtde.getTransferable();
			} catch (Exception e) {
				LogUtilities.error(e.getMessage(), e);
			}
			if (transferable == null) {
				return;
			}
			JViewport vp = (JViewport) tree.getParent();

			Point vpMousePosition = dtde.getLocation();
			// 将树中的坐标转换为scrollPanel里的坐标，为scrollPanel做铺垫
			vpMousePosition = SwingUtilities.convertPoint(tree, vpMousePosition, vp.getParent());
			Rectangle treeVisibleRectangle = tree.getVisibleRect();

			Integer newY = null;
			// 确保滚动条没有一直向下滚动
			if (tree.getHeight() - treeVisibleRectangle.y != vp.getHeight()) {
				// 获取向下滚动的Y坐标
				if (vp.getHeight() - vpMousePosition.y < 30 && vp.getHeight() - vpMousePosition.y > 0) {
					newY = treeVisibleRectangle.y + (30 + vpMousePosition.y - vp.getHeight()) * 2;
				}
			}

			// 确保滚动条没有一直向上滚动
			if (newY == null && treeVisibleRectangle.y != 0) {
				// 获取向上滚动的Y坐标
				if (30 > vpMousePosition.y && vpMousePosition.y > 0) {
					newY = treeVisibleRectangle.y - (30 - vpMousePosition.y) * 2;
				}
			}

			// 滚动
			if (newY != null) {
				Rectangle treeNewVisibleRectangle = new Rectangle(treeVisibleRectangle.x, newY, treeVisibleRectangle.width, treeVisibleRectangle.height);
				tree.scrollRectToVisible(treeNewVisibleRectangle);
			}

			Point dragPoint = dtde.getLocation();
			if (dragPoint == null) {
				return;
			}
			TreePath treePath = tree.getPathForLocation(dragPoint.x, dragPoint.y);
			DefaultMutableTreeNode dropTargetNode = null;
			if (null == treePath) {
				// 获取到的树节点treePath为null，清除绘制拖拽标识线
				clearRecordBounds((Graphics2D) getGraphics());
			} else {
				dropTargetNode = (DefaultMutableTreeNode) treePath.getLastPathComponent();
				Rectangle pathBounds = tree.getPathBounds(treePath);
				if (pathBounds != null) {
					// 判断当前目标节点是偏节点的顶部还是底部区域
					isUp = !(dragPoint.getY() > (pathBounds.y + pathBounds.height / 2));
				}
				// 绘制移动标识线
				repaintTree(dropTargetNode);
			}
		}

		private void clearRecordBounds(Graphics2D graphics2D) {
			if (this.recordBounds != null) {
				// 清除绘制区域
				boolean rowSelected = tree.isRowSelected(tree.getRowForLocation(this.recordBounds.x, this.recordBounds.y));
				graphics2D.setColor(rowSelected ? ColorUtilities.getHighlightColor() : tree.getBackground());
				if (this.recordBounds.height > 0) {
					graphics2D.drawRect(this.recordBounds.x, this.recordBounds.y, this.recordBounds.width, this.recordBounds.height);
				} else {
					graphics2D.drawLine(this.recordBounds.x, this.recordBounds.y, this.recordBounds.x + this.recordBounds.width, this.recordBounds.y);
				}
			}
		}

		private void repaintTree(DefaultMutableTreeNode dropTargetNode) {
			Graphics2D graphics2D = (Graphics2D) tree.getGraphics();
			TreePath treePath = new TreePath(dropTargetNode.getPath());
			Rectangle bounds = tree.getPathBounds(treePath);
			if (isUp) {
				bounds.setBounds(bounds.x, bounds.y, bounds.width, 0);
				if (this.recordBounds != null && !bounds.equals(this.recordBounds)) {
					clearRecordBounds(graphics2D);
				}
				graphics2D.setColor(MOVE_COLOR);
				graphics2D.drawLine(bounds.x, bounds.y, bounds.x + bounds.width, bounds.y);
			} else {
				bounds.setBounds(bounds.x, bounds.y + bounds.height, bounds.width, 0);
				if (this.recordBounds != null && !bounds.equals(this.recordBounds)) {
					clearRecordBounds(graphics2D);
				}
				graphics2D.setColor(MOVE_COLOR);
				graphics2D.drawLine(bounds.x, bounds.y + bounds.height, bounds.x + bounds.width, bounds.y + bounds.height);
			}
			this.recordBounds = bounds;
			JLabel label = (JLabel) tree.getCellRenderer().getTreeCellRendererComponent(tree, dropTargetNode.getUserObject(), false, tree.isExpanded(treePath), tree.getModel().isLeaf(dropTargetNode), tree.getRowForPath(treePath), false);
			label.repaint();
		}

		// 拖拽释放
		@Override
		public void drop(DropTargetDropEvent dtde) {
			if (!isDropAcceptable(dtde)) {
				dtde.rejectDrop();
				return;
			}
			Transferable transferable = null;
			try {
				transferable = dtde.getTransferable();
			} catch (Exception e) {
				LogUtilities.error(e.getMessage(), e);
			}
			if (transferable == null) {
				return;
			}
			try {
				DataFlavor[] dataFlavors = transferable.getTransferDataFlavors();
				if (transferable.isDataFlavorSupported(dataFlavors[0])) {
					for (DataFlavor dataFlavor : dataFlavors) {
						if (dataFlavor == null) {
							continue;
						}
						// 如果拖入的是树节点
						if (dataFlavor.equals(TREE_SORT_DRAG_NODE)) {
							Point location = dtde.getLocation();
							TreePath pathForLocation = tree.getPathForLocation(location.x, location.y);// 获取鼠标所在位置的树节点TreePath
							if (pathForLocation != null && pathForLocation.getLastPathComponent() instanceof DefaultMutableTreeNode) {
								DefaultMutableTreeNode targetMutableTreeNode = (DefaultMutableTreeNode) pathForLocation.getLastPathComponent();
								Object[] userObjects = (Object[]) transferable.getTransferData(dataFlavor);
								DefaultMutableTreeNode rootNode = (DefaultMutableTreeNode) tree.getModel().getRoot();
								DefaultMutableTreeNode[] defaultMutableTreeNodes = new DefaultMutableTreeNode[userObjects.length];
								for (int i = 0; i < userObjects.length; i++) {
									defaultMutableTreeNodes[i] = findTreeNode(rootNode, userObjects[i]);
								}
								DefaultMutableTreeNode targetParent = (DefaultMutableTreeNode) targetMutableTreeNode.getParent();
								int index = targetParent.getIndex(targetMutableTreeNode);
								// 是偏上就移动到树节点上面，如果是偏下就移动到当前树节点下面
								if (isUp) {
									for (int i = 0; i < defaultMutableTreeNodes.length; i++) {
										DefaultMutableTreeNode defaultMutableTreeNode = defaultMutableTreeNodes[i];
										((DefaultTreeModel) tree.getModel()).removeNodeFromParent(defaultMutableTreeNode);// 先从父节点移除
										((DefaultTreeModel) tree.getModel()).insertNodeInto(defaultMutableTreeNode, targetParent, index);
										index = index + 1;
									}
								} else {
									index = index + 1;
									for (int i = 0; i < defaultMutableTreeNodes.length; i++) {
										DefaultMutableTreeNode defaultMutableTreeNode = defaultMutableTreeNodes[i];
										if (targetParent == defaultMutableTreeNode.getParent()) {// 如果同一个父节点下的向下移动，需要考虑到前面的移除后插入后后面，index得减-1
											index = index - 1;
										}
										((DefaultTreeModel) tree.getModel()).removeNodeFromParent(defaultMutableTreeNode);// 先从父节点移除
										((DefaultTreeModel) tree.getModel()).insertNodeInto(defaultMutableTreeNode, targetParent, index);
										index = index + 1;
									}
								}
								// 选中拖拽移动后的节点
								TreePath[] treePaths = new TreePath[defaultMutableTreeNodes.length];
								for (int i = 0; i < treePaths.length; i++) {
									treePaths[i] = new TreePath(defaultMutableTreeNodes[i].getPath());
								}
								tree.scrollPathToVisible(treePaths[treePaths.length - 1]);
								tree.setSelectionPaths(treePaths);
							}
						}
					}
				}
			} catch (Exception e) {
				Application.getActiveApplication().getOutput().output(e);
			}
		}
	}


	class TreeTransferHandler extends TransferHandler {

		@Override
		public int getSourceActions(JComponent c) {
			return MOVE;// 支持移动，继而可以拖拽树节点
		}

		@Override
		protected Transferable createTransferable(JComponent c) {
			// 移动时（拖拽）会进入这里，创建一个Transferable持有拖拽的数据
			if (null != tree.getLastSelectedPathComponent()) {
				DefaultMutableTreeNode treeNode = (DefaultMutableTreeNode) tree.getLastSelectedPathComponent();
				if (null != treeNode && null != treeNode.getUserObject()) {
					DefaultMutableTreeNode[] treeNodes = new DefaultMutableTreeNode[tree.getSelectionCount()];
					TreePath[] selectionPaths = tree.getSelectionPaths();
					if (selectionPaths != null) {
						for (int i = 0; i < selectionPaths.length; i++) {
							treeNodes[i] = (DefaultMutableTreeNode) selectionPaths[i].getLastPathComponent();
						}
					}
					return new TreeTransferable(treeNodes);
				}
			}
			return null;
		}
	}

	class TreeTransferable extends SmTransferable {

		private final DefaultMutableTreeNode[] treeNodes;
		private Object[] data = null;

		public TreeTransferable(DefaultMutableTreeNode... treeNodes) {
			// 可以根据不同的数据节点使用不同的类型，该 Demo 是拖拽树节点，持有树节点的UserObject，方便拖拽，数据类型使用TREE_SORT_DRAG_NODE
			this.treeNodes = treeNodes;
			this.data = new Object[this.treeNodes.length];
			for (int i = 0; i < treeNodes.length; i++) {
				this.data[i] = treeNodes[i].getUserObject();
			}
			this.dataFlavor = TREE_SORT_DRAG_NODE;// 设置数据类型
		}

		// 获取持有的数据
		@Override
		public Object getData() {
			return this.data;
		}
	}

}
